package com.oocl.euc.core.requestform.service;

import com.oocl.euc.authentication.core.SSOAuthority;
import com.oocl.euc.common.constant.*;
import com.oocl.euc.common.utils.UserContextHolder;
import com.oocl.euc.core.attachment.model.Attachment;
import com.oocl.euc.core.maintenance.model.EmailTemplate;
import com.oocl.euc.core.maintenance.model.SubCategory;
import com.oocl.euc.core.maintenance.repository.EmailTemplateRepository;
import com.oocl.euc.core.maintenance.service.EmailTemplateService;
import com.oocl.euc.core.requestform.model.*;
import com.oocl.euc.core.requestform.repository.RequestFormRepository;
import com.oocl.euc.core.requestform.repository.SubCategoryRepository;
import com.oocl.euc.framework.base.persistence.IBaseRepository;
import com.oocl.euc.framework.base.service.BaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class RequestFormService extends BaseService<RequestForm, Long> {

    private static Logger logger = LoggerFactory.getLogger(RequestFormService.class);

    @Autowired
    RequestFormRepository requestFormRepository;
    @Autowired
    RequestSeqConfigService requestSeqConfigService;

    @Autowired
    private EmailTemplateService emailTemplateService;

    @Autowired
    private EmailTemplateRepository emailTemplateRepository;

    @Autowired
    private SubCategoryRepository subCategoryRepository;

    @Autowired
    private EmailSenderService emailSenderService;

    @Autowired
    private RequestRemarksService requestRemarksService;

    @Override
    protected IBaseRepository<RequestForm, Long> getRepository() {
        return requestFormRepository;
    }

    @Transactional(rollbackFor = Exception.class)
    public RequestForm createRequestForm(RequestForm requestForm) throws Exception {

        RequestSeqConfig requestSeqConfig = requestSeqConfigService.generateRequestSeq(ApplicationConstant.PCRS_PREFIX);
        String refNo = String.format("%06d", requestSeqConfig.getCurrentNo());

        requestForm.setRefNO(refNo);
        requestForm.setRefNumber(requestSeqConfig.getCurrentNo());
        requestForm.setRequestStatus(RequestFormStatus.PENDING);

        List<RequestPostmortem> requestPostmortemList = requestForm.getRequestpostmortem();
        setPostmortemRefNO(refNo, requestPostmortemList);

        List<RequestAttachment> requestAttachmentList = requestForm.getRequestattachments();
        setRequestAttachmentRefNO(refNo, requestAttachmentList);

        List<RequestProcedures> requestProceduresList = requestForm.getRequestprocedures();
        setProceduresRefNO(refNo, requestProceduresList);

        List<Attachment> attachmentList = new ArrayList<>();
        if (requestAttachmentList != null) {
            attachmentList = requestAttachmentList.stream().map(RequestAttachment::getAttachment).collect(Collectors.toList());
        }

        RequestForm form = requestFormRepository.save(requestForm);
        emailSenderService.sendEmail(MailTemplateKey.ACK_EMAIL, requestForm, attachmentList);
        requestRemarksService.saveRemark(requestForm, MailTemplateKey.ACK_EMAIL);
        logFormInfoAndLogSendEmail(form);
        return form;
    }

    public RequestForm updateRequestForm(RequestForm requestForm) throws MessagingException {
        String requestType = requestForm.getRequestType();
        if (RequestFormStatus.ENDORSED.equals(requestType)) {
            return endorsePcrsForm(requestForm);
        } else if (RequestFormStatus.REJECTED.equals(requestType)) {
            return rejectPcrsForm(requestForm);
        } else if (RequestFormStatus.WITHDRAWN.equals(requestType)) {
            return withDrawPcrsForm(requestForm);
        } else if (RequestFormStatus.REVIEWED.equals(requestType)) {
            return reviewPcrsForm(requestForm);
        } else if (RequestFormStatus.WAITING_FOR_PP.equals(requestType)) {
            return waitingPcrsForm(requestForm);
        } else if (RequestFormStatus.PENDING.equals(requestType)) {
            return pendingPcrsForm(requestForm);
        } else {
            return updatePcrsForm(requestForm);
        }
    }

    public RequestForm updatePcrsForm(RequestForm requestForm) throws MessagingException {
        String refNo = requestForm.getRefNO();
        RequestForm originForm = findRequestFormByRefNO(refNo);
        handleChanged(requestForm, originForm);
        setSeqAndProgressForTaskStatusProgress(requestForm);

        //Automatically approve
        if (!RequestFormStatus.APPROVED.equals(originForm.getRequestStatus())) {
            approveAutomatically(requestForm);
        }

        autoClose(requestForm, originForm);

        //HKCTR changes pcrs status
        if (isFieldChange(requestForm.getRequestStatus(), originForm.getRequestStatus()) && isHKCTR() && RequestFormStatus.PENDING.equals(requestForm.getRequestStatus())) {
            resetApproverAndEndorserAction(requestForm, PPTrialRunResult.SUCCESS.equals(requestForm.getPpTrialRunResult()) && requestForm.getWorkingProcedureChanged());
            resetOnlineServiceImpact(requestForm);
        }

        //if the contents changed , status to pending and send repending email
        if (!RequestFormStatus.NEW.equals(originForm.getRequestStatus()) && (requestForm.getImportantFieldIsChanged() || requestForm.getWorkingProcedureChanged() || requestForm.getIsPPNeedToPending() || requestForm.getIsQANeedToPending())) {
            requestForm.setApprovalCategoryIsNeeded(null);
            requestForm.setApprovalIsNeeded(null);
            if (!isApprover(requestForm)) {
                requestForm.setRequestStatus(RequestFormStatus.PENDING);
                requestForm.setApproveQATestResult(null);
                requestForm.setApprovePPRunResult(null);
                requestForm.setEndorsedBy(null);
                if (!RequestFormStatus.PENDING.equals(originForm.getRequestStatus()) && requestForm.getWorkingProcedureChanged() && PPTrialRunResult.SUCCESS.equals(requestForm.getPpTrialRunResult())) {
                    requestForm.setPpTrialRunResult(PPTrialRunResult.PROGRESS);
                }
            }
            circulateOnlineService(requestForm);
        }

        if (requestForm.getIsQANeedToPending()) {
            requestForm.setApproveQATestResult(null);
        }

        if (requestForm.getIsPPNeedToPending()) {
            requestForm.setApprovePPRunResult(null);
        }

        if (requestForm.getIsAcceptPP()) {
            requestRemarksService.saveRemark(requestForm, MailTemplateKey.ACCEPT_NO_PP);
        }

        if (requestForm.getIsAcceptQA()) {
            requestRemarksService.saveRemark(requestForm, MailTemplateKey.ACCEPT_NO_QA);
        }

        //change online service content or change from 'Yes' to 'No'
        if (ApplicationConstant.NO.equals(hasOnlineServiceImpact(requestForm)) && requestForm.getApproveOnlineServiceImpact() != null) {
            requestForm.setApproveOnlineServiceImpact(null);
            requestForm.setApprovalIsNeeded(null);
            requestForm.setApproveImpactBy(null);
        }
        RequestForm result = requestFormRepository.save(requestForm);
        sendEmail(result, originForm);
        logFormInfoAndLogSendEmail(result);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public RequestForm endorsePcrsForm(RequestForm requestForm) throws MessagingException {
        this.setAllRequestProceduresSeq(requestForm);
        circulateOnlineService(requestForm);
        endorseEmail(requestForm);
        logFormInfoAndLogSendEmail(requestForm);
        emailSenderService.sendEmail(MailTemplateKey.ENDORSED_EMAIL, requestForm);
        return requestFormRepository.save(requestForm);

    }

    private void endorseEmail(RequestForm item) {
        item.setCirculatedAt(new Date());
        if (item.getIsAcceptPP()) {
            requestRemarksService.saveRemark(item, MailTemplateKey.ACCEPT_NO_PP);
        }

        if (item.getIsAcceptQA()) {
            requestRemarksService.saveRemark(item, MailTemplateKey.ACCEPT_NO_QA);
        }
        requestRemarksService.saveRemark(item, MailTemplateKey.ENDORSED_EMAIL);
    }

    public RequestForm rejectPcrsForm(RequestForm requestForm) throws MessagingException {
        EmailTemplate template = emailTemplateService.findByEmailTempalteKey(MailTemplateKey.REJECTED_EMAIL);
        if (template != null) {
            emailSenderService.send(template, requestForm);
        }
        logFormInfoAndLogSendEmail(requestForm);
        return requestFormRepository.save(requestForm);
    }


    public RequestForm withDrawPcrsForm(RequestForm requestForm) throws MessagingException {
        EmailTemplate template = emailTemplateService.findByEmailTempalteKey(MailTemplateKey.WITHDRAWN_EMAIL);
        if (template != null) {
            emailSenderService.send(template, requestForm);
        }
        logFormInfoAndLogSendEmail(requestForm);
        return requestFormRepository.save(requestForm);
    }

    public RequestForm pendingPcrsForm(RequestForm requestForm) throws MessagingException {
        String refNo = requestForm.getRefNO();
        RequestForm originForm = findRequestFormByRefNO(refNo);
        handleChanged(requestForm, originForm);

        resetApproverAndEndorserAction(requestForm, PPTrialRunResult.SUCCESS.equals(requestForm.getPpTrialRunResult()));
        circulateOnlineService(requestForm);
        requestRemarksService.saveRemark(requestForm, MailTemplateKey.CHGCNTL_PENGING_EMAIL);
        emailSenderService.sendEmail(MailTemplateKey.CHGCNTL_PENGING_EMAIL, requestForm);
        logFormInfoAndLogSendEmail(requestForm);
        return requestFormRepository.save(requestForm);
    }

    public RequestForm reviewPcrsForm(RequestForm requestForm) throws MessagingException {
        String refNo = requestForm.getRefNO();
        RequestForm originForm = findRequestFormByRefNO(refNo);
        handleChanged(requestForm, originForm);
        circulateOnlineService(requestForm);
        boolean canApprove = canApprove(requestForm);
        //automatically approve
        if ((RequestFormStatus.ENDORSED.equals(originForm.getRequestStatus()) || RequestFormStatus.WAITING_FOR_PP.equals(originForm.getRequestStatus())) && canApprove) {
            requestForm.setRequestStatus(RequestFormStatus.APPROVED);
        }

        requestRemarksService.saveRemark(requestForm, MailTemplateKey.REVIEWED_EMAIL);

        emailSenderService.sendEmail(MailTemplateKey.REVIEWED_EMAIL, requestForm);
        logFormInfoAndLogSendEmail(requestForm);
        return requestFormRepository.save(requestForm);
    }

    public RequestForm waitingPcrsForm(RequestForm requestForm) throws MessagingException {
        String refNo = requestForm.getRefNO();
        RequestForm originForm = findRequestFormByRefNO(refNo);
        handleChanged(requestForm, originForm);

        circulateOnlineService(requestForm);
        requestRemarksService.saveRemark(requestForm, MailTemplateKey.WAITING_FOR_PP);
        emailSenderService.sendEmail(MailTemplateKey.WAITING_FOR_PP, requestForm);
        logFormInfoAndLogSendEmail(requestForm);
        return requestFormRepository.save(requestForm);
    }

    private void sendEmail(RequestForm requestForm, RequestForm originForm) throws MessagingException {

        String emailTemplateKey = getEmailTemplateByOldAndNewForm(requestForm, originForm);
        //Send Email when HKCTR changes pcrs status
        if (isFieldChange(requestForm.getRequestStatus(), originForm.getRequestStatus()) && isHKCTR()) {
            if (RequestFormStatus.PENDING.equals(requestForm.getRequestStatus())) {
                /* sendEmailNotify(MailTemplateKey.CHGCNTL_PENGING_EMAIL, requestForm); */
            } else if ("".equals(emailTemplateKey)) {
                requestRemarksService.saveRemark(requestForm, MailTemplateKey.CHGCNTL_CHANGER_STATUS_EMAIL);
            }
        }

        if (!emailTemplateKey.isEmpty()) {
            try {
                sendEmailNotify(emailTemplateKey, requestForm);
            } catch (MessagingException e) {
                logger.error("RequestFormService",e);
                throw e;
            }
        }
    }

    private void setProceduresRefNO(String refNo, List<RequestProcedures> requestProceduresList) {
        if (requestProceduresList != null) {

            for (RequestProcedures requestProcedures : requestProceduresList) {

                requestProcedures.setRefNo(refNo);
            }
        }
    }

    private void setRequestAttachmentRefNO(String refNo, List<RequestAttachment> requestAttachmentList) {
        if (requestAttachmentList != null) {

            for (RequestAttachment requestAttachment : requestAttachmentList) {

                requestAttachment.setRefNo(refNo);
            }
        }
    }

    private void setPostmortemRefNO(String refNo, List<RequestPostmortem> requestPostmortemList) {
        if (requestPostmortemList != null) {

            for (RequestPostmortem postmortemItem : requestPostmortemList) {

                postmortemItem.setRefNo(refNo);
                List<RequestPostmortemAttach> postmortemAttachList = postmortemItem.getPostmortemAttach();
                if (postmortemAttachList != null) {

                    for (RequestPostmortemAttach postmortemAttachItem : postmortemAttachList) {

                        postmortemAttachItem.setRefNo(refNo);
                    }
                }
            }
        }
    }

    private void resetOnlineServiceImpact(RequestForm requestForm) {
        requestForm.setApproveImpactBy(null);
        requestForm.setApproveOnlineServiceImpact(null);
        circulateOnlineService(requestForm);
    }

    private String getEmailTemplateByOldAndNewForm(RequestForm requestForm, RequestForm originForm) {
        String emailTemplateKey = "";
        if (!RequestFormStatus.PENDING.equals(originForm.getRequestStatus()) && !RequestFormStatus.NEW.equals(originForm.getRequestStatus()) && RequestFormStatus.PENDING.equals(requestForm.getRequestStatus())) {
            resetApproverAndEndorserAction(requestForm, PPTrialRunResult.SUCCESS.equals(requestForm.getPpTrialRunResult()) && requestForm.getWorkingProcedureChanged());
            circulateOnlineService(requestForm);
            return emailTemplateKey;
        }

        if (RequestFormStatus.NEW.equals(originForm.getRequestStatus()) && RequestFormStatus.PENDING.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.ACK_EMAIL;
            circulateOnlineService(requestForm);
        } else if (!RequestFormStatus.ENDORSED.equals(originForm.getRequestStatus()) && RequestFormStatus.ENDORSED.equals(requestForm.getRequestStatus())) {
            requestForm.setEndorsedBy(requestForm.getUpdatedBy().getStaffId());
            requestForm.setEndorsedAt(requestForm.getUpdatedAt());
            emailTemplateKey = MailTemplateKey.ENDORSED_EMAIL;
            //change by fiona
            if (ApplicationConstant.YES.equals(hasOnlineServiceImpact(requestForm)) && !ApplicationConstant.YES.equals(requestForm.getApproveOnlineServiceImpact()))
                emailTemplateKey = "";
        } else if (!RequestFormStatus.WITHDRAWN.equals(originForm.getRequestStatus()) && RequestFormStatus.WITHDRAWN.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.WITHDRAWN_EMAIL;
        } else if (!RequestFormStatus.REJECTED.equals(originForm.getRequestStatus()) && RequestFormStatus.REJECTED.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.REJECTED_EMAIL;
        } else if (!RequestFormStatus.APPROVED.equals(originForm.getRequestStatus()) && RequestFormStatus.APPROVED.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.APPROVED_EMAIL;
        } else if (!RequestFormStatus.SUCCESS.equals(originForm.getRequestStatus()) && RequestFormStatus.SUCCESS.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.SUCCESS_EMAIL;
        } else if (!RequestFormStatus.PARTIAL_SUCCESS.equals(originForm.getRequestStatus()) && RequestFormStatus.PARTIAL_SUCCESS.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.PARTIAL_SUCCESS_EMAIL;
        } else if (!RequestFormStatus.FAILED.equals(originForm.getRequestStatus()) && RequestFormStatus.FAILED.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.FAILED_EMAIL;
        } else if (!RequestFormStatus.CANCELLED.equals(originForm.getRequestStatus()) && RequestFormStatus.CANCELLED.equals(requestForm.getRequestStatus())) {
            emailTemplateKey = MailTemplateKey.CANCELLED_EMAIL;
        }

        return emailTemplateKey;
    }

    private void resetApproverAndEndorserAction(RequestForm requestForm, Boolean resetPPStatusCondition) {
        requestForm.setApprovalCategoryIsNeeded(null);
        requestForm.setApprovalIsNeeded(null);
        requestForm.setApproveQATestResult(null);
        requestForm.setApprovePPRunResult(null);
        requestForm.setEndorsedBy(null);
        if (resetPPStatusCondition) {
            requestForm.setPpTrialRunResult(PPTrialRunResult.PROGRESS);
        }
    }

    public void setSeqAndProgressForTaskStatusProgress(RequestForm form) {
        setAllRequestProceduresSeq(form);
        setTaskStatusProgress(form);
    }

    public void setTaskStatusProgress(RequestForm form) {
        Boolean bHasInProgress = false;
        Boolean bHasSkip = false;
        Boolean bHasCompleted = false;
        Boolean bHasError = false;
        Boolean bHasFallback = false;
        Boolean bBlank = false;
        List<RequestProcedures> requestProcedures = form.getWorkingProcedures();
        for (RequestProcedures r : requestProcedures) {
            if (r != null)
                if (r.getTaskStatus() != null) {
                    if (r.getTaskStatus().equals(TaskStatus.STATUS_IN_PROGRESS)) {
                        bHasInProgress = true;
                    } else if (r.getTaskStatus().equals(TaskStatus.STATUS_SKIP)) {
                        bHasSkip = true;
                    } else if (r.getTaskStatus().equals(TaskStatus.STATUS_COMPLETED)) {
                        bHasCompleted = true;
                    } else if (r.getTaskStatus().equals(TaskStatus.STATUS_FALLBACK)) {
                        bHasFallback = true;
                    } else if (r.getTaskStatus().equals(TaskStatus.STATUS_ERROR)) {
                        bHasError = true;
                    } else {
                        bBlank = true;
                    }
                } else
                    bBlank = true;
        }

        //If all task status = 'select' then Change Progress = blank(default setting)
        if (!bHasInProgress && !bHasSkip && !bHasCompleted && !bHasFallback && !bHasError) {
            form.setProgress("");
        } else {
            //If any one of task status not = 'select' and at least one other task = 'select' then Change Progress = 'In Progress'
            //If any status is 'In progress', the change progress must be 'In progress' as well even some of the status is 'Error' or 'Fallback'.
            if (bBlank || bHasInProgress)
                form.setProgress(TaskStatus.STATUS_IN_PROGRESS);
            else if (bHasError)//If at least one of task status ='Error' and remaining tasks = 'Completed' or 'Skip' or 'Fallback' then Change Progress = 'Error'
                form.setProgress(TaskStatus.STATUS_ERROR);
            else if (bHasFallback)//If any one of task status ='Fallback' and remaining tasks = 'Completed' or 'Skip' then Change Progress = 'Fallback'
                form.setProgress(TaskStatus.STATUS_FALLBACK);
            else if (!(bBlank || bHasInProgress || bHasSkip || bHasFallback || bHasError))//If all task status = 'completed' then Change Progress = 'Completed'
                form.setProgress(TaskStatus.STATUS_COMPLETED);
            else if (!(bBlank || bHasInProgress || bHasCompleted || bHasFallback || bHasError))//If all task status = 'skip' then Change Progress = 'Skip'
                form.setProgress(TaskStatus.STATUS_SKIP);
            else if (bHasCompleted && !(bBlank || bHasInProgress || bHasFallback || bHasError))//If any one task status = 'completed' and all remaining task status = 'completed' or 'skip' then Change Progress = 'Completed'
                form.setProgress(TaskStatus.STATUS_COMPLETED);
            else
                form.setProgress(TaskStatus.STATUS_IN_PROGRESS);
        }
    }

    private void setAllRequestProceduresSeq(RequestForm form) {
        setRequestProceduresSequence(form.getWorkingProcedures());
        setRequestProceduresSequence(form.getVerifyProcedures());
        setRequestProceduresSequence(form.getRecoveryProcedures());
    }

    private void setRequestProceduresSequence(List<RequestProcedures> verifyProcedures) {
        Integer iSeqProcedure;
        iSeqProcedure = 0;
        for (RequestProcedures r : verifyProcedures) {
            iSeqProcedure = iSeqProcedure + 1;
            r.setProcedureSeq(iSeqProcedure);
            r.setHandledBy(r.getHandledBy() == null ? "" : r.getHandledBy().trim());
            r.setContactNo(r.getContactNo() == null ? "" : r.getContactNo().trim());
        }
    }

    public RequestForm findRequestFormByRefNO(String refNO) {
        return requestFormRepository.findByRefNO(refNO);
    }

    private void sendEmailNotify(String emailTemplateKey, RequestForm requestForm) throws MessagingException {
        EmailTemplate template = emailTemplateService.findByEmailTempalteKey(emailTemplateKey);
        if (template != null) {
            emailSenderService.send(template, requestForm);
        }
    }

    //automatically approve : reviewed , pp and qa success or accpeted, RA Progress is Completed if Risk Level is High or Medium
    public void approveAutomatically(RequestForm requestForm) {
        Date formattedDate = getRequestFormExpectedDate(requestForm);
        boolean isAfterApproveTime = false;
        if (formattedDate != null) {
            isAfterApproveTime = formattedDate.getTime() - new Date().getTime() > 0;
        }
        boolean canAutoApprove = false;
        if (isApprover(requestForm)) {
            canAutoApprove = RequestFormStatus.REVIEWED.equals(requestForm.getRequestStatus());
        } else {
            canAutoApprove = RequestFormStatus.REVIEWED.equals(requestForm.getRequestStatus()) && isAfterApproveTime && !requestForm.getImportantFieldIsChanged() && !requestForm.getWorkingProcedureChanged();
        }

        if (canAutoApprove && canApprove(requestForm)) {
            requestForm.setRequestPreStatus(requestForm.getRequestStatus());
            requestForm.setRequestStatus(RequestFormStatus.APPROVED);
        }
    }

    private boolean canApprove(RequestForm requestForm) {
        String testingResult = requestForm.getTestingResult();
        String ppResult = requestForm.getPpTrialRunResult();
        String approveNoQA = requestForm.getApproveQATestResult();
        String approveNoPP = requestForm.getApprovePPRunResult();
        if (((QATestingResult.NO_NEED_TEST.equals(testingResult) && ApplicationConstant.YES.equals(approveNoQA)) || QATestingResult.SUCCESS.equals(testingResult)) && ((PPTrialRunResult.NOTEST.equals(ppResult) && ApplicationConstant.YES.equals(approveNoPP)) || PPTrialRunResult.SUCCESS.equals(ppResult))) {
            boolean isAutoApproveforRisk = true;
            if (requestForm.getRiskLevel() != null
                    && (RequestFormRiskAssessment.RISK_LEVEL_MEDIUM.equals(requestForm.getRiskLevel()) || RequestFormRiskAssessment.RISK_LEVEL_HIGH.equals(requestForm.getRiskLevel()))) {
                isAutoApproveforRisk = RequestFormRiskAssessment.RA_PROGRESS_COMPLETED.equals(requestForm.getRiskAssessmentProgress());
            }
            if (isAutoApproveforRisk) {
                if (requestForm.getOnlineServiceImpact() != null && !requestForm.getOnlineServiceImpact().isEmpty()) {
                    if (requestForm.getApproveImpactBy() != null || !ApplicationConstant.YES.equals(requestForm.getApprovalIsNeeded())) {
                        return true;
                    }
                } else {
                    return true;
                }
            }
        }
        return false;
    }

    private void autoClose(RequestForm item, RequestForm originForm) {
        String requestStatus = item.getRequestStatus();
        boolean isRightStatus = RequestFormStatus.APPROVED.equals(requestStatus) || RequestFormStatus.FAILED.equals(requestStatus) || RequestFormStatus.PARTIAL_SUCCESS.equals(requestStatus) || RequestFormStatus.SUCCESS.equals(requestStatus);
        String firstVerifyResult = item.getFirstVerificationResult();
        String sencondVerifyResult = item.getVerificationResult();
        boolean isFinishVefify = !"".equals(firstVerifyResult) && !"".equals(sencondVerifyResult);
        if (isRightStatus && isFinishVefify && isCompleted(item) && originForm.getRequestStatus().equals(requestStatus)) {
            String progress = item.getProgress();
            boolean isSuccessProgress = TaskStatus.STATUS_COMPLETED.equals(progress) || TaskStatus.STATUS_SKIP.equals(progress) || (TaskStatus.STATUS_ERROR.equals(progress) && item.getIsApprover());
            if (VerificationResult.SUCCESS.equals(firstVerifyResult) && VerificationResult.SUCCESS.equals(sencondVerifyResult) && isSuccessProgress) {
                item.setRequestStatus(RequestFormStatus.SUCCESS);
            } else if (VerificationResult.FAIL.equals(firstVerifyResult) || VerificationResult.FAIL.equals(sencondVerifyResult)) {
                item.setRequestStatus(RequestFormStatus.FAILED);
            } else if (VerificationResult.PARTIAL_SUCCESS.equals(firstVerifyResult) || VerificationResult.PARTIAL_SUCCESS.equals(sencondVerifyResult)) {
                item.setRequestStatus(RequestFormStatus.PARTIAL_SUCCESS);
            }
        }
    }

    public void circulateOnlineService(RequestForm requestForm) {
        requestForm.setApprovalIsNeeded(null);
        SubCategory subCategory = subCategoryRepository.findByCategoryIdAndSubCategoryId(requestForm.getCategoryId(), requestForm.getSubcategoryId());
        if (subCategory != null && !"".equals(subCategory.getDistribution())) {
            requestForm.setApprovalCategoryIsNeeded(ApplicationConstant.YES);
        } else {
            requestForm.setApprovalCategoryIsNeeded(ApplicationConstant.NO);
        }
        if (ApplicationConstant.YES.equals(requestForm.getApprovalIsNeeded())) {
            if (ApplicationConstant.YES.equals(hasOnlineServiceImpact(requestForm)) && ApplicationConstant.YES.equals(requestForm.getApproveOnlineServiceImpact())) {
                requestForm.setApproveOnlineServiceImpact(ApplicationConstant.NO);
            }
        } else {
            requestForm.setApproveOnlineServiceImpact(null);
        }
    }

    //changed by fiona
    public String hasOnlineServiceImpact(RequestForm item) {
        String hasOnlineServiceImpact = ApplicationConstant.NO;
        if (item.getOnlineServiceImpact() != null && !item.getOnlineServiceImpact().isEmpty()) {
            hasOnlineServiceImpact = ApplicationConstant.YES;
        }
        return hasOnlineServiceImpact;
    }

    //changed by fiona
    public Boolean isCompleted(RequestForm item) {
        String progress = item.getProgress();
        return !"".equals(progress) && !TaskStatus.STATUS_IN_PROGRESS.equals(progress);
    }

    private Date getRequestFormExpectedDate(RequestForm item) {
        Date formattedDate = null;
        try {
            DateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");
            String strExpecteDate = dateFormat.format(item.getExpectedDate()) + " " + item.getExpectedTime();
            DateFormat dateGmtFormat = new SimpleDateFormat("dd-MMM-yyyy HH:mm");
            formattedDate = dateGmtFormat.parse(strExpecteDate);
        } catch (ParseException e) {
            logger.error("RequestFormService",e);
        }
        return formattedDate;
    }

    public Boolean isFieldChange(Object a, Object b) {
        if (a == null && b == null)
            return false;
        else if ((a == null && "".equals(b)) || ("".equals(a) && b == null)) {
            return false;
        } else if (a == null || b == null)
            return true;
        else
            return !a.equals(b);
    }

    public void handleChanged(RequestForm requestForm, RequestForm originForm) {

        handleImportantFieldIsChanged(requestForm, originForm);
        handleWorkingProcedureChanged(requestForm, originForm);
        handleQATestingResultChanged(requestForm, originForm);
        handlePpTrialRunResultChanged(requestForm,originForm);
    }

    public void handleImportantFieldIsChanged(RequestForm requestForm, RequestForm originForm) {

        if (isFieldChange(requestForm.getExpectedDate(), originForm.getExpectedDate()) || isFieldChange(requestForm.getExpectedTime(), originForm.getExpectedTime())) {

            requestForm.setImportantFieldIsChanged(true);
        }

        if (isFieldChange(requestForm.getCategoryId(), originForm.getCategoryId()) || isFieldChange(requestForm.getSubcategoryId(), originForm.getSubcategoryId())) {

            requestForm.setImportantFieldIsChanged(true);
        }

        if (isFieldChange(requestForm.getOnlineServiceImpact(), originForm.getOnlineServiceImpact())
                || isFieldChange(requestForm.getOnlineServiceImpactFromDate(), originForm.getOnlineServiceImpactFromDate())
                || isFieldChange(requestForm.getOnlineServiceImpactToDate(), originForm.getOnlineServiceImpactToDate())) {

            requestForm.setImportantFieldIsChanged(true);
        }
    }

    public void handleWorkingProcedureChanged(RequestForm requestForm, RequestForm originForm) {

        if (isFieldChange(requestForm.getWorkingProcedures().size(), originForm.getWorkingProcedures().size())) {
            requestForm.setWorkingProcedureChanged(true);
        }
        //todo: update the value for workingProcedure
    }

    public void handleQATestingResultChanged(RequestForm requestForm, RequestForm originForm) {

        String newTestResult = requestForm.getTestingResult();
        String oldTestResult = originForm.getTestingResult();
        if (!"".equals(newTestResult) && !"".equals(oldTestResult) && isFieldChange(newTestResult, oldTestResult)) {
            requestForm.setQaTestingResultIsChanged(true);
            if ((QATestingResult.SUCCESS.equals(originForm.getTestingResult()) && isFieldChange(requestForm.getTestingResult(), (originForm.getTestingResult())))
                    || (QATestingResult.PROGRESS.equals(originForm.getTestingResult()) && QATestingResult.NO_NEED_TEST.equals(requestForm.getTestingResult()))) {
                requestForm.setIsQANeedToPending(true);
            }
        }
    }

    public void handlePpTrialRunResultChanged(RequestForm requestForm, RequestForm originForm) {

        String newPpTrialRunResult = requestForm.getPpTrialRunResult();
        String oldPpTrialRunResult = originForm.getPpTrialRunResult();
        if (!"".equals(newPpTrialRunResult) && !"".equals(oldPpTrialRunResult) && isFieldChange(newPpTrialRunResult, oldPpTrialRunResult)) {
            requestForm.setPpRunResultIsChanged(true);
            if ((QATestingResult.SUCCESS.equals(oldPpTrialRunResult) && isFieldChange(newPpTrialRunResult, (oldPpTrialRunResult)))
                    || (QATestingResult.PROGRESS.equals(oldPpTrialRunResult) && QATestingResult.NO_NEED_TEST.equals(newPpTrialRunResult))) {
                requestForm.setIsPPNeedToPending(true);
            }
        }
    }

    public boolean isApprover(RequestForm requestForm) {

        List<SSOAuthority> roles = UserContextHolder.getUserContext().getRoles();
        if (roles != null) {

            boolean isChgCtl = UserContextHolder.getUserContext().getRoles().stream().anyMatch(role -> Objects.equals(role.getAuthority(), RoleEnum.APPROVER.value()) ||
                    Objects.equals(role.getAuthority(), RoleEnum.HKCTR.value()));
            if (isChgCtl && !UserContextHolder.getUserContext().getUserInfo().getDomainId().equals(requestForm.getRequesterDomainId())) {

                requestForm.setIsApprover(true);
            }
        }
        return requestForm.getIsApprover();
    }

    private Boolean isHKCTR() {
        Boolean isHKCTR = false;
        List<SSOAuthority> roles = UserContextHolder.getUserContext().getRoles();
        if (roles != null) {
            isHKCTR = UserContextHolder.getUserContext().getRoles().stream().anyMatch(role -> Objects.equals(role.getAuthority(), RoleEnum.HKCTR.value()));
        }
        return isHKCTR;
    }

    private void logFormInfoAndLogSendEmail(RequestForm form) {
        logger.info("submit form ref no", form.getRefNO());
        logger.info("submit form id", form.getId());
        logger.info("submit form status", form.getRequestStatus());
        logger.info("email have send for status", form.getRequestStatus());
    }
}
